﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace TaskFramework
{
    public class TaskTracker : ITaskTracker
    {
        private readonly Dictionary<int, int> _tasks = new Dictionary<int, int>();
        private readonly Dictionary<int, int> _taskRefCount = new Dictionary<int, int>();

        private void FireRootTaskRemovedEvent(int rootTaskId)
        {
            if (RootTaskDead != null)
            {
                foreach (RootTaskDeadHandler handler in RootTaskDead.GetInvocationList())
                {
                    try
                    {
                        handler.Invoke(rootTaskId);
                    }
                    catch (Exception) { }
                }
            }
        }

        public void AddTask(int taskId)
        {
            AddTask(taskId, taskId);
        }

        public void AddTask(int taskId, int routedByTaskId)
        {
            int rootId;
            if (_tasks.ContainsKey(routedByTaskId))
            {
                rootId = _tasks[routedByTaskId];
            }
            else
            {
                rootId = routedByTaskId;
            }

            if (_tasks.ContainsKey(taskId))
            {
                _tasks[taskId] = rootId;
            }
            else
            {
                _tasks.Add(taskId, rootId);
            }

            if (!_taskRefCount.ContainsKey(rootId))
            {
                _taskRefCount.Add(rootId, 0);
            }

            _taskRefCount[rootId]++;
        }

        public int ResolveRootTaskId(int taskId)
        {
            if (!_tasks.ContainsKey(taskId))
            {
                throw new TaskNotTrackedException();
            }

            return _tasks[taskId];
        }

        public void RemoveTask(int taskId)
        {
            int rootTaskId = _tasks[taskId];

            if (--_taskRefCount[rootTaskId] == 0)
            {
                List<int> tasksToRemove = new List<int>();
                foreach (KeyValuePair<int, int> pair in _tasks)
                {
                    if (pair.Value == rootTaskId)
                    {
                        tasksToRemove.Add(pair.Key);
                    }
                }

                foreach (int id in tasksToRemove)
                {
                    _tasks.Remove(id);
                }

                _taskRefCount.Remove(rootTaskId);
                FireRootTaskRemovedEvent(rootTaskId);
            }
        }

        public bool IsTracked(int taskId)
        {
            return _tasks.ContainsKey(taskId);
        }

        public event RootTaskDeadHandler RootTaskDead;
    }
}
